﻿using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;

namespace AutoCadConvert
{
    public static class Extension
    {
        public static IEnumerable<T> Clone<T>(this IEnumerable<T> listToClone) where T : ICloneable
        {
            return listToClone.Select(o => (T)o.Clone()).ToList();
        }
        //执行命令
        public static PromptStatus Command(this Editor ed, params object[] args)
        {
            if (ed == null)
                throw new ArgumentNullException("ed");
            return RunCommand(ed, args);
        }
        static Func<Editor, object[], PromptStatus> RunCommand = GenerateRunCommand();
        static Func<Editor, object[], PromptStatus> GenerateRunCommand()
        {
            MethodInfo method = typeof(Editor).GetMethod(
                "RunCommand", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
            ParameterExpression instance = Expression.Parameter(typeof(Editor), "ed");
            ParameterExpression args = Expression.Parameter(typeof(object[]), "args");
            return Expression.Lambda<Func<Editor, object[], PromptStatus>>(
               Expression.Call(instance, method, args), instance, args)
                  .Compile();
        }
        //获取图层名称
        public static ObjectId GetLayerObjectId(this Database db, string layerName)
        {
            LayerTable lt = (LayerTable)db.LayerTableId.GetObject(OpenMode.ForRead);
            //if (!lt.Has(layerName))
            //{
            //    LayerTableRecord ltr = new LayerTableRecord();
            //    ltr.Name = layerName;
            //    lt.UpgradeOpen();
            //    lt.Add(ltr);

            //    db.TransactionManager.AddNewlyCreatedDBObject(ltr, true);
            //    lt.DowngradeOpen();
            //}
            if (lt.Has(layerName))
                return lt[layerName];
            else
                return ObjectId.Null;
        }
        //设置图层名称
        public static void SetLayer(this Database db, string layerName)
        {
            LayerTable lt = (LayerTable)db.LayerTableId.GetObject(OpenMode.ForRead);
            if (lt.Has(layerName))
            {
                db.Clayer = lt[layerName];
            }
        }
        //添加Block属性
        public static void AddAttsToBlocks(this BlockReference block, List<AttributeDefinition> atts)
        {
            Database db = block.Database;//获取数据库对象
            BlockTableRecord btr = db.TransactionManager.GetObject(block.BlockTableRecord, OpenMode.ForRead) as BlockTableRecord;
            btr.UpgradeOpen();
            foreach (AttributeDefinition att in atts)
            {
                btr.AppendEntity(att);
                db.TransactionManager.AddNewlyCreatedDBObject(att, true);
            }
            db.TransactionManager.Dispose();
            btr.DowngradeOpen();
        }
        //添加Block属性
        public static void AddAttributeDefinitionToBlocks(this ObjectId blockId, List<AttributeDefinition> atts)
        {
            Database db = blockId.Database;//获取数据库对象
            BlockTableRecord btr = blockId.GetObject(OpenMode.ForWrite) as BlockTableRecord;
            foreach (AttributeDefinition att in atts)
            {
                btr.AppendEntity(att);
                db.TransactionManager.AddNewlyCreatedDBObject(att, true);
            }
            db.TransactionManager.Dispose();
            btr.DowngradeOpen();
        }
        //修改Block属性
        public static void UpdateAttributesInBlock(this BlockReference blockRef, Dictionary<string, string> attNameValues)
        {
            foreach (ObjectId id in blockRef.AttributeCollection)
            {
                AttributeReference attref = id.GetObject(OpenMode.ForRead) as AttributeReference;
                if (attNameValues.ContainsKey(attref.Tag.ToUpper()))
                {
                    attref.UpgradeOpen();
                    //设置属性值
                    attref.TextString = attNameValues[attref.Tag.ToUpper()].ToString();
                    attref.DowngradeOpen();
                }
            }
        }
        //查询属性
        public static string GetValueAttributesInBlock(this BlockReference blockRef, string attNameValue)
        {
            foreach (ObjectId id in blockRef.AttributeCollection)
            {
                AttributeReference attref = id.GetObject(OpenMode.ForRead) as AttributeReference;
                if (attNameValue.ToUpper() == attref.Tag.ToUpper())
                {
                    //设置属性值
                    return attref.TextString;
                }
            }
            return "";
        }
        //添加属性
        public static void AddAttributeToBlockTableRecord(this BlockTableRecord blokRec, BlockReference blockRef, Dictionary<string,string> atts)
        {
            if (!blokRec.HasAttributeDefinitions)//添加属性定义
                blokRec.ObjectId.AddAttributeDefinitionToBlocks(new List<AttributeDefinition>() {
                            new AttributeDefinition(){ Tag=""} });
            //foreach (ObjectId id in blokRec)
            {
                foreach (KeyValuePair<string,string> attribute in atts)
                {
                    if (blockRef.GetValueAttributesInBlock(attribute.Key) == "")
                    {
                        AttributeReference attRef = new AttributeReference() { Tag = attribute.Key, TextString = attribute.Value };
                        blockRef.AttributeCollection.AppendAttribute(attRef);
                        blockRef.Database.TransactionManager.AddNewlyCreatedDBObject(attRef, true);
                        attRef.Dispose();
                    }
                    else
                    {
                        blockRef.UpdateAttributesInBlock(new Dictionary<string, string>() { { attribute.Key, attribute.Value } });
                    }
                }
            }
        }
        public static BlockReference ReferenceOuterFileBlock(this BlockTableRecord blokRec, Autodesk.AutoCAD.Geometry.Point3d pt,string file,string name)
        {
            ObjectId refid = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Database.AttachXref(file, name);
            //ObjectId refid = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Database.OverlayXref(file, name);// 通过外部文件获取图块定义的ObjectId
            BlockReference blockRef = new BlockReference(pt, refid); // 通过块定义添加块参照
            blokRec.AppendEntity(blockRef); //把块参照添加到块表记录
            blockRef.Database.TransactionManager.AddNewlyCreatedDBObject(blockRef, true); // 通过事务添加块参照到数据库
            return blockRef;
        }
        public static BlockReference ImportOuterFileBlock(this BlockTableRecord blokRec, Autodesk.AutoCAD.Geometry.Point3d pt,string file,string name)
        {
            //Database sourceDb = new Database(false, true);
            //sourceDb.ReadDwgFile(file, FileShare.Read, true, "");
            //ObjectIdCollection blockIds = new ObjectIdCollection();
            //using (Transaction ts = database.TransactionManager.StartTransaction())
            //{
            //    BlockTable bt = (BlockTable)ts.GetObject(sourceDb.BlockTableId, OpenMode.ForRead, false);
            //    foreach (ObjectId btrId in bt)
            //    {
            //        BlockTableRecord btr = (BlockTableRecord)ts.GetObject(btrId, OpenMode.ForRead, false);
            //        if (!btr.IsAnonymous && !btr.IsLayout)
            //            blockIds.Add(btrId);
            //        btr.Dispose();
            //    }
            //    IdMapping mapping = new IdMapping();
            //    sourceDb.WblockCloneObjects(blockIds, database.BlockTableId, mapping, DuplicateRecordCloning.Replace, false);
            //}
            //sourceDb.Dispose();
            if (!File.Exists(file)) throw new Exception(string.Format("\n文件找不到：{0}",file));
            using (Database sourceDb = new Database(false, false))
            {
                sourceDb.ReadDwgFile(file, FileShare.Read, true, "");
                sourceDb.CloseInput(true);
                ObjectId blockId = blokRec.Database.Insert(name, sourceDb, false);
                BlockReference blockRef = new BlockReference(pt, blockId); // 通过块定义添加块参照
                blokRec.AppendEntity(blockRef); //把块参照添加到块表记录
                blockRef.Database.TransactionManager.AddNewlyCreatedDBObject(blockRef, true);
                return blockRef;
            }
        }
    }
}
